package edu.unice.simul.modele;

import java.util.ArrayList;
import java.util.List;

import edu.unice.simul.modele.contenus.Contenu;
import edu.unice.simul.modele.contenus.immobiles.Immobile;
import edu.unice.simul.modele.contenus.immobiles.Mur;
import edu.unice.simul.modele.contenus.immobiles.Sortie;
import edu.unice.simul.modele.contenus.mobiles.Humain;
import edu.unice.simul.util.Dim;

/**
 * Classe modélisant la pièce correspondante à la simulation
 * 
 * @author Romain Ciaccafava
 * 
 */
public class Piece {
	/**
	 * Dimensions de la pièce
	 */
	private Dim dimensions;
	/**
	 * Contenu de la pièce
	 */
	private List<Contenu> contenu = new ArrayList<Contenu>();

	public Piece(Dim dimmensions) {
		this.dimensions = dimmensions;
	}

	public Piece(Piece piece) {
		this.dimensions = piece.dimensions;
		for (Contenu c : piece.contenu) {
			if (c instanceof Mur)
				contenu.add(new Mur(c.getPosition()));
			else if (c instanceof Humain) {
				Humain h = new Humain(c.getPosition(), c.getDirection(),
						((Humain) c).getPiece());
				h.setPrcVie(((Humain) c).getPrcVie());
				h.setAge(((Humain) c).getAge());
				h.setSociabilite(((Humain) c).getSociabilite());
				contenu.add(h);
			} else if (c instanceof Sortie)
				contenu.add(new Sortie(c.getPosition()));
		}
	}

	public Dim getDimmensions() {
		return this.dimensions;
	}

	public List<Contenu> getContenu() {
		return this.contenu;
	}

	/**
	 * Prend en paramètre un objet Dim modélisant la position de l'element et
	 * renvoie une liste de contenu se trouvant à cette position.
	 */
	public List<Contenu> getContenuAt(Dim pos) {
		List<Contenu> result = new ArrayList<Contenu>();

		if (pos.getX() < 0 || pos.getY() < 0 || pos.getX() >= dimensions.getX()
				|| pos.getY() >= dimensions.getY())
			result.add(new Mur(pos));
		else
			for (Contenu c : contenu) {
				Dim tmp = c.getPosition(); // recupère position

				if (tmp.equals(pos))
					result.add(c);
			}

		return result;
	}

	/**
	 * Retourne la liste des humains présents dans la pièce
	 */
	public List<Humain> getHumains() {
		List<Humain> list = new ArrayList<Humain>();

		for (Contenu c : contenu)
			if (c instanceof Humain)
				list.add((Humain) c);

		return list;
	}

	/**
	 * Retourne la liste des sorties présentes dans la pièce
	 */
	public List<Sortie> getSorties() {
		List<Sortie> list = new ArrayList<Sortie>();

		for (Contenu c : contenu)
			if (c instanceof Sortie)
				list.add((Sortie) c);
		return list;
	}

	/**
	 * Retourne la liste des immobiles présents dans la pièce
	 */
	public List<Immobile> getImmobiles() {
		List<Immobile> list = new ArrayList<Immobile>();

		for (Contenu c : contenu)
			if (c instanceof Immobile)
				list.add((Immobile) c);

		for (int i = -1; i <= dimensions.getX(); i++) {
			list.add(new Mur(new Dim(i, -1)));
			list.add(new Mur(new Dim(i, dimensions.getY())));
		}

		for (int i = 0; i < dimensions.getY(); i++) {
			list.add(new Mur(new Dim(-1, i)));
			list.add(new Mur(new Dim(dimensions.getX(), i)));
		}

		return list;
	}

	/**
	 * Ajoute un contenu à la pièce
	 */
	public void ajouterContenu(Contenu c) {
		if (c.getPosition().getX() > dimensions.getX()
				|| c.getPosition().getX() < 0
				|| c.getPosition().getY() > dimensions.getY()
				|| c.getPosition().getY() < 0)
			throw new IllegalArgumentException("Coordonnées en dehors de la pièce.");
		contenu.add(c);
	}

	/**
	 * Retourne le nombre d'humains dans la pièce
	 */
	public int getNumberOfMobiles() {
		int nb = 0;

		for (Contenu c : contenu)
			if (c instanceof Humain && !((Humain) c).estSorti())
				nb++;

		return nb;
	}

	/**
	 * Retourne le nombre de morts dans la pièce
	 */
	public int getNombreDeMorts() {
		int morts = 0;
		List<Humain> humains = getHumains();
		for (Humain h : humains)
			if (!h.enVie())
				morts++;

		return morts;
	}

	/**
	 * Retourne le nombre d'humains encore en vie
	 */
	public int getNombreDeVivants() {
		int enVie = 0;
		List<Humain> humains = getHumains();
		for (Humain h : humains)
			if (h.enVie())
				enVie++;

		return enVie;
	}
}
